import 'bean/card_bean.dart';
import 'bean/player_bean.dart';
import 'bean/texas_bean.dart';

class CardUtils {
  static const noPair = 0;
  static const pair = 1;
  static const twoPairs = 2;
  static const trips = 3;
  static const straight = 4;
  static const flush = 5;
  static const fullHouse = 6;
  static const quads = 7;
  static const straightFlush = 8;
  static const royalStraightFlush = 9;

  static String getTypeStr(PlayerBean playerBean, TexasBean curBean) {
    return getTypeString(recogniseType(playerBean, curBean));
  }

  static String getTypeString(int type) {
    var typeString;
    switch (type) {
      case noPair:
        typeString = "高牌";
        break;
      case pair:
        typeString = "一对";
        break;
      case twoPairs:
        typeString = "两对";
        break;
      case trips:
        typeString = "三条";
        break;
      case straight:
        typeString = "顺子";
        break;
      case flush:
        typeString = "同花";
        break;
      case fullHouse:
        typeString = "葫芦";
        break;
      case quads:
        typeString = "金刚";
        break;
      case straightFlush:
        typeString = "同花顺";
        break;
      case royalStraightFlush:
        typeString = "皇家同花顺";
        break;
      default:
        typeString = "unknown";
    }
    return typeString;
  }

  ///获取牌的类型
  static int recogniseType(PlayerBean playerBean, TexasBean curBean) {
    int type = noPair;
    List<CardBean> allCards = getAllCards(playerBean, curBean);
    allCards = sort(allCards);
    if (isRoyalStraightFlush(allCards)) {
      type = royalStraightFlush;
    } else if (isStraightFlush(allCards)) {
      type = straightFlush;
    } else if (isQuads(allCards)) {
      type = quads;
    } else if (isFullHouse(allCards)) {
      type = fullHouse;
    } else if (isFlush(allCards)) {
      type = flush;
    } else if (isStraight(allCards)) {
      type = straight;
    } else if (isTrips(allCards)) {
      type = trips;
    } else if (isTwoPairs(allCards)) {
      type = twoPairs;
    } else if (isPair(allCards)) {
      type = pair;
    } else {
      type = noPair;
    }
    return type;
  }

  ///是否是一对
  static bool isPair(List<CardBean> allCards) {
    int count = 0;
    int curNum = 0;
    for (var cardBean in allCards) {
      if (cardBean.num != curNum) {
        count = 1;
        curNum = cardBean.num;
      } else {
        count++;
        if (count > 1) {
          return true;
        }
      }
    }
    return false;
  }

  ///是否是两对
  static bool isTwoPairs(List<CardBean> allCards) {
    int count = 0;
    int curNum = 0;
    int pairNum = 0;
    for (var cardBean in allCards) {
      if (cardBean.num != curNum) {
        count = 1;
        curNum = cardBean.num;
      } else {
        count++;
        if (count == 2) {
          pairNum++;
        }
      }
    }
    if (pairNum > 1) {
      return true;
    }
    return false;
  }

  ///是否是三条
  static bool isTrips(List<CardBean> allCards) {
    int count = 0;
    int curNum = 0;
    for (var cardBean in allCards) {
      if (cardBean.num != curNum) {
        count = 1;
        curNum = cardBean.num;
      } else {
        count++;
        if (count > 2) {
          return true;
        }
      }
    }
    return false;
  }

  ///是否是顺子
  static bool isStraight(List<CardBean> allCards) {
    int count = 0;
    int curNum = 0;
    for (var cardBean in allCards) {
      if (cardBean.num == curNum) {
        continue;
      } else if (cardBean.num == curNum - 1) {
        count++;
        if (count > 4) {
          return true;
        }
      } else {
        count = 1;
      }
      curNum = cardBean.num;
    }
    return false;
  }

  ///是否是同花
  static bool isFlush(List<CardBean> allCards) {
    int count = 0;
    int curSuit = -1;
    List<CardBean> suitCards = sortAsSuit(allCards);
    for (CardBean cardBean in suitCards) {
      if (cardBean.suit != curSuit) {
        count = 1;
        curSuit = cardBean.suit;
      } else {
        count++;
        if (count > 4) {
          return true;
        }
      }
    }
    return false;
  }

  ///是否是葫芦
  static bool isFullHouse(List<CardBean> allCards) {
    int count = 0;
    int curNum = 0;
    int tripleNum = 0;
    int pairNum = 0;
    for (CardBean cardBean in allCards) {
      if (cardBean.num != curNum) {
        count = 1;
        curNum = cardBean.num;
      } else {
        count++;
        if (count == 3) {
          tripleNum = curNum;
          break;
        }
      }
    }
    count = 0;
    curNum = 0;
    for (CardBean cardBean in allCards) {
      if (cardBean.num != curNum) {
        count = 1;
        curNum = cardBean.num;
      } else {
        count++;
        if (count == 2 && curNum != tripleNum) {
          pairNum = curNum;
          break;
        }
      }
    }
    if (tripleNum != 0 && pairNum != 0) {
      return true;
    }
    return false;
  }

  ///是否是金刚
  static bool isQuads(List<CardBean> allCards) {
    int count = 0;
    int curNum = 0;
    for (var cardBean in allCards) {
      if (cardBean.num != curNum) {
        count = 1;
        curNum = cardBean.num;
      } else {
        count++;
        if (count > 3) {
          return true;
        }
      }
    }
    return false;
  }

  ///是否是同花顺
  static bool isStraightFlush(List<CardBean> allCards) {
    int count = 0;
    int curSuit = -1;
    List<CardBean> suitCards = sortAsSuit(allCards);
    for (CardBean cardBean in suitCards) {
      if (cardBean.suit != curSuit) {
        count = 1;
        curSuit = cardBean.suit;
      } else {
        count++;
        if (count > 4) {
          break;
        }
      }
    }
    count = 0;
    int curNum = 0;
    for (CardBean cardBean in allCards) {
      if (cardBean.suit == curSuit) {
        if (cardBean.num == curNum) {
          continue;
        } else if (cardBean.num == curNum - 1) {
          count++;
          if (count > 4) {
            return true;
          }
        } else {
          count = 1;
        }
        curNum = cardBean.num;
      }
    }
    return false;
  }

  ///是否是皇家同花顺
  static bool isRoyalStraightFlush(List<CardBean> allCards) {
    int count = 0;
    int curSuit = -1;
    int maxStraightNum = 0;
    List<CardBean> suitCards = sortAsSuit(allCards);
    for (var cardBean in suitCards) {
      if (cardBean.suit != curSuit) {
        count = 1;
        curSuit = cardBean.suit;
      } else {
        count++;
        if (count > 4) {
          break;
        }
      }
    }
    count = 0;
    int curNum = 2;
    for (var cardBean in allCards) {
      if (cardBean.suit == curSuit) {
        if (cardBean.num == curNum) {
          continue;
        } else if (cardBean.num == curNum - 1) {
          count++;
          if (count > 4 && maxStraightNum == 14) {
            return true;
          }
        } else {
          count = 1;
          maxStraightNum = cardBean.num;
        }
        curNum = cardBean.num;
      }
    }
    return false;
  }

  static List<CardBean> sortAsSuit(List<CardBean> allCards) {
    List<CardBean> result = new List<CardBean>();
    result.add(allCards[0]);
    for (int i = 1; i < allCards.length; i++) {
      bool ifInsert = false;
      for (int j = 0; j < result.length; j++) {
        if (allCards[i].suit > result[j].suit) {
          result.insert(j, allCards[i]);
          ifInsert = true;
          break;
        }
      }
      if (!ifInsert) {
        result.add(allCards[i]);
      }
    }
    return result;
  }

  static List<CardBean> sort(List<CardBean> allCards) {
    List<CardBean> result = new List<CardBean>();
    if (allCards.isNotEmpty) result.add(allCards[0]);
    for (int i = 1; i < allCards.length; i++) {
      bool ifInsert = false;
      for (int j = 0; j < result.length; j++) {
        if (allCards[i].num > result[j].num) {
          result.insert(j, allCards[i]);
          ifInsert = true;
          break;
        }
      }
      if (!ifInsert) {
        result.add(allCards[i]);
      }
    }
    return result;
  }

  static List<CardBean> getAllCards(PlayerBean playerBean, TexasBean curBean) {
    List<CardBean> allCards = new List<CardBean>();
    allCards.addAll(playerBean.hands);
    for (CardBean cardBean in curBean.flops) {
      allCards.add(cardBean);
    }
    allCards.add(curBean.turn);
    allCards.add(curBean.river);
    return allCards;
  }

  static List<CardBean> getCardResultList(
      PlayerBean playerBean, TexasBean curBean) {
    List<CardBean> allCards = getAllCards(playerBean, curBean);
    List<CardBean> resultCards;
    allCards = sort(allCards);
    int type = recogniseType(playerBean, curBean);
    switch (type) {
      case 0:
        resultCards = getHighResultList(allCards);
        break;
      case 1:
        resultCards = getPairResultList(allCards);
        break;
      case 2:
        resultCards = getTwoPairResultList(allCards);
        break;
      case 3:
        resultCards = getTripsResultList(allCards);
        break;
      case 4:
        resultCards = getStraightResultList(allCards);
        break;
      case 5:
        resultCards = getFlushResultList(allCards);
        break;
      case 6:
        resultCards = getFullHouseResultList(allCards);
        break;
      case 7:
        resultCards = getQuadsResultList(allCards);
        break;
      case 8:
        resultCards = getFlushStraightResultList(allCards);
        break;
      case 9:
        resultCards = getRoyalFlushStraightResultList(allCards);
        break;
      default:
        resultCards = new List();
    }
    return resultCards;
  }

  static List<CardBean> getHighResultList(List<CardBean> allCards) {
    List<CardBean> results = new List();
    results.addAll(allCards.getRange(0, 5));
    return results;
  }

  static List<CardBean> getPairResultList(List<CardBean> allCards) {
    List<CardBean> results = new List();
    int count = 0;
    CardBean curCard = allCards[0];
    for (var cardBean in allCards) {
      if (cardBean.num != curCard.num) {
        count = 1;
        curCard = cardBean;
      } else {
        count++;
        if (count > 1) {
          results.add(curCard);
          results.add(cardBean);
          break;
        }
      }
    }
    for (var card in allCards) {
      if (!results.contains(card)) {
        results.add(card);
      }
      if (results.length == 5) {
        break;
      }
    }
    return results;
  }

  static List<CardBean> getTwoPairResultList(List<CardBean> allCards) {
    List<CardBean> results = new List();
    int count = 0;
    CardBean curCard = allCards[0];
    CardBean pairCardOne;
    CardBean pairCardOne2;
    CardBean pairCardTwo;
    CardBean pairCardTwo2;
    for (var cardBean in allCards) {
      if (cardBean.num != curCard.num) {
        count = 1;
        curCard = cardBean;
      } else {
        count++;
        if (count > 1) {
          pairCardOne = curCard;
          pairCardOne2 = cardBean;
          break;
        }
      }
    }
    for (var cardBean in allCards) {
      if (cardBean.num != curCard.num) {
        count = 1;
        curCard = cardBean;
      } else {
        count++;
        if (count > 1 && curCard.num != pairCardOne.num) {
          pairCardTwo = curCard;
          pairCardTwo2 = cardBean;
          break;
        }
      }
    }
    if (pairCardOne.num > pairCardTwo.num) {
      results.add(pairCardOne);
      results.add(pairCardOne2);
      results.add(pairCardTwo);
      results.add(pairCardTwo2);
    } else {
      results.add(pairCardTwo);
      results.add(pairCardTwo2);
      results.add(pairCardOne);
      results.add(pairCardOne2);
    }
    allCards.remove(pairCardOne);
    allCards.remove(pairCardOne2);
    allCards.remove(pairCardTwo);
    allCards.remove(pairCardTwo2);
    results.add(allCards.first);
    return results;
  }

  static List<CardBean> getTripsResultList(List<CardBean> allCards) {
    List<CardBean> results = new List();
    int count = 0;
    int curNum = 0;
    for (var cardBean in allCards) {
      if (cardBean.num != curNum) {
        count = 1;
        curNum = cardBean.num;
      } else {
        count++;
        if (count > 2) {
          break;
        }
      }
    }
    for (var cardBean in allCards) {
      if (cardBean.num == curNum) {
        results.add(cardBean);
      }
    }
    for (var cardBean in allCards) {
      if (cardBean.num != curNum && results.length < 5) {
        results.add(cardBean);
      }
    }
    return results;
  }

  static List<CardBean> getStraightResultList(List<CardBean> allCards) {
    List<CardBean> results = new List();
    int count = 0;
    int curNum = 0;
    for (var cardBean in allCards) {
      if (cardBean.num == curNum) {
        continue;
      } else if (cardBean.num == curNum - 1) {
        count++;
        if (count > 4) {
          curNum = cardBean.num;
          break;
        }
      } else {
        count = 1;
      }
      curNum = cardBean.num;
    }
    var num = curNum + 4;
    for (var i = num; i >= curNum; i--) {
      for (var card in allCards) {
        if (card.num == i) {
          results.add(card);
          break;
        }
      }
    }

    return results;
  }

  static List<CardBean> getFlushResultList(List<CardBean> allCards) {
    List<CardBean> results = new List();
    int count = 0;
    int curSuit = -1;
    List<CardBean> suitCards = sortAsSuit(allCards);
    for (CardBean cardBean in suitCards) {
      if (cardBean.suit != curSuit) {
        count = 1;
        curSuit = cardBean.suit;
      } else {
        count++;
        if (count > 4) {
          curSuit = cardBean.suit;
          break;
        }
      }
    }
    for (var cardBean in allCards) {
      if (cardBean.suit == curSuit && results.length < 5) {
        results.add(cardBean);
      }
    }
    return results;
  }

  static List<CardBean> getFullHouseResultList(List<CardBean> allCards) {
    List<CardBean> results = new List();
    int count = 0;
    int curNum = 0;
    int tripleNum = 0;
    int pairNum = 0;
    for (CardBean cardBean in allCards) {
      if (cardBean.num != curNum) {
        count = 1;
        curNum = cardBean.num;
      } else {
        count++;
        if (count == 3) {
          tripleNum = curNum;
          break;
        }
      }
    }
    count = 0;
    curNum = 0;
    for (CardBean cardBean in allCards) {
      if (cardBean.num != curNum) {
        count = 1;
        curNum = cardBean.num;
      } else {
        count++;
        if (count == 2 && curNum != tripleNum) {
          pairNum = curNum;
          break;
        }
      }
    }
    for (var card in allCards) {
      if (card.num == tripleNum) {
        results.add(card);
      }
    }
    for (var card in allCards) {
      if (card.num == pairNum) {
        results.add(card);
      }
    }
    return results;
  }

  static List<CardBean> getQuadsResultList(List<CardBean> allCards) {
    List<CardBean> results = new List();
    int count = 0;
    int curNum = 0;
    for (var cardBean in allCards) {
      if (cardBean.num != curNum) {
        count = 1;
        curNum = cardBean.num;
      } else {
        count++;
        if (count > 3) {
          curNum = cardBean.num;
          break;
        }
      }
    }
    for (var card in allCards) {
      if (card.num == curNum) {
        results.add(card);
      } else if (results.length == 4) {
        results.add(card);
        break;
      }
    }
    return results;
  }

  static List<CardBean> getFlushStraightResultList(List<CardBean> allCards) {
    List<CardBean> results = new List();
    int count = 0;
    int curSuit = -1;
    List<CardBean> suitCards = sortAsSuit(allCards);
    for (CardBean cardBean in suitCards) {
      if (cardBean.suit != curSuit) {
        count = 1;
        curSuit = cardBean.suit;
      } else {
        count++;
        if (count > 4) {
          curSuit = cardBean.suit;
          break;
        }
      }
    }
    count = 0;
    int curNum = 0;
    for (CardBean cardBean in allCards) {
      if (cardBean.suit == curSuit) {
        if (cardBean.num == curNum) {
          continue;
        } else if (cardBean.num == curNum - 1) {
          count++;
          if (count > 4) {
            curNum = cardBean.num;
            break;
          }
        } else {
          count = 1;
        }
        curNum = cardBean.num;
      }
    }
    for (var card in allCards) {
      if (card.suit == curSuit &&
          card.num <= curNum + 4 &&
          card.num >= curNum) {
        results.add(card);
      }
    }
    return results;
  }

  static List<CardBean> getRoyalFlushStraightResultList(
      List<CardBean> allCards) {
    List<CardBean> results = new List();
    results.addAll(allCards.getRange(0, 5));
    return results;
  }
}
